#ifndef __REVENG_SEMAPHORE_HPP__
#define __REVENG_SEMAPHORE_HPP__

#include <RevEng/ObjRef.hpp>
#include <RevEng/ICondVar.hpp>
#include <RevEng/IMutex.hpp>

namespace RevEng
{
	class Semaphore
	{
	protected:
		ObjRef<IMutex> m_Guard;
		Int32 m_nMaxThreads;

		ObjRef<ICondVar> m_FreeSlot;
		Int32 m_nThreads;

	public:
		Semaphore() : 
			m_nMaxThreads(0), 
			m_nThreads(0)
		{
			m_FreeSlot	= static_cast<ICondVar*>(IObject::New( REVENG_CONDVAR ));
			m_Guard		= static_cast<IMutex*>(IObject::New( REVENG_MUTEX ));
		}

		void Lock()
		{
			m_Guard->Lock();

			if (m_nThreads + 1 > m_nMaxThreads)
				m_FreeSlot->Wait( m_Guard );
			else
				++m_nThreads;

			m_Guard->Unlock();
		}


		void Unlock()
		{
			m_Guard->Lock();

			if (m_nThreads > 0)
			{
				--m_nThreads;
				m_FreeSlot->Signal();
			}
			else
			{
				//Invalid operation
			}

			m_Guard->Unlock();
		}

		void SetCapacity(Int32 Cap)
		{
			m_Guard->Lock();

			if (m_nThreads == 0)
				m_nMaxThreads = Cap;

			m_Guard->Unlock();
		}


		Int32 GetCapacity() const 
		{
			return m_nMaxThreads;
		}
	};
}

#endif	//__REVENG_SEMAPHORE_HPP__
